/* + C O P Y R I G H T * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* See top source directory for COPYRIGHT.txt                              */
/* Copyright 2002-2003 by Mark Wolgemuth, All rights reserved.             */
/* Copyright 2002-2003 by Employease, Inc.  All rights reserved.           */
/* - C O P Y R I G H T * * * * * * * * * * * * * * * * * * * * * * * * * * */


#ifndef ATHD_TYPES_H
#define ATHD_TYPES_H

#include "apr_thread_proc.h"
#include "apr_hash.h"

#include "ath_types.h"
#include "athd_util_types.h"
#include "serf.h"
#include "pthread.h"
#include "apr_errno.h"


/* job duration */
#define ATHD_JOB_ETERNAL       -1

#define ATHD_JOB_STR_NON       "nojobtype"
#define ATHD_JOB_STR_MON       "monitor"
#define ATHD_JOB_STR_MIR       "mirror"
#define ATHD_JOB_STR_AGT       "agent"

/* important core limits */
#define ATHD_MAX_PROGARGS      32   /* limit arg arrays */
#define ATHD_BUF_SIZE          1024 /* used in misc buffers */
#define ATHD_TICK              1000 /* in millisex */
#define ATHD_WETDREAM          10000000 /* 10 seconds */

/* error codes */
/* evidently a closed keep alive conn causes this (bad address) */
#define ATHD_BAD_KEEPALIVE     (APR_OS_START_ERROR + 14)

/* error messages */
#define ATHD_ERR_NULL          "No error message."
#define ATHD_ERR_MISSARG       "Missing argument."
#define ATHD_ERR_BADLOGFAC     "Invalid syslog fac. Use {user|daemon|local0->3}."
#define ATHD_ERR_INVALARG      "Invalid argument."
#ifdef HAVE_GETPGRP
#define ATHD_ERR_PROCRUN       "ERROR: Athena already running at pgid [%d]!"
#else
#define ATHD_ERR_PROCRUN       "ERROR: Athena already running at pid [%d]!"
#endif /* HAVE_GETPGRP */
#define ATHD_ERR_MANYARGS      "Too many args to program"
#define ATHD_ERR_CFPROP        "ERROR: LINE: %d Property: %s Value: %s Why: %s"
#define ATHD_ERR_DPROP         "ERROR: -D Property: %s Value: %s Why: %s"
#define ATHD_ERR_NOPROP        "ERROR: Property does not exist: %s (IGNORING)"
#define ATHD_ERR_JOBEXST       "ERROR: Job previously declared"
#define ATHD_ERR_JOBNONE       "ERROR: Job does not exist."
#define ATHD_ERR_JOBNTYPE      "ERROR: No such job type."
#define ATHD_ERR_ENGEXST       "ERROR: Engine previously declared."
#define ATHD_ERR_ENGNONE       "ERROR: Engine does not exist."
#define ATHD_ERR_ENGOONE       "ERROR: Only one engine per job."
#define ATHD_ERR_GID           "Gid only works AFTER Uid"
#define ATHD_WARN_UID          "WARN: Uid not set, using default: %s"
#define ATHD_WARN_JOBEXST      "WARN: Job exists: %s"
#define ATHD_WARN_ENGEXST      "WARN: Engine exists: %s"
#define ATHD_WARN_STALEPID     "WARN: Stale pid file [%s] cleaned up, previous unclean shutdown?"
/* cmd io errors */
#define ATHD_ERR_IOSNDLIM      "Cmd io: SEND exceeds limit, nothing sent."
#define ATHD_ERR_IORCVLIM      "Cmd io: RECV exceeds limit, aborting recv."

/* cmd parser errors */
#define ATHD_ERR_NOCTX         "ERROR: You are not currently in a command context.\n"
#define ATHD_ERR_NOTIMPL       "ERROR: Command not implemented in this context.\n"
#define ATHD_ERR_NOENG         "ERROR: Engine not configured.\n"
#define ATHD_ERR_NOJOB         "ERROR: Job not configured.\n"
#define ATHD_ERR_ENGCTX        "ERROR: Engine context required.\n"
#define ATHD_ERR_BADFARM       "ERROR: Farm deserialization error.\n"
#define ATHD_ERR_BADPHYS       "ERROR: Phys deserialization error.\n"
#define ATHD_ERR_NOCMD         "ERROR: Unknown command. Type \"help\" for help.\n"
#define ATHD_ERR_CTXAGAIN      "ERROR: Already in [%s] context.\n"
#define ATHD_ERR_NOFARM        "ERROR: Farm not in engine.\n"

/* taken from apache httpd.h */
/** @} */
/* Just in case your linefeed isn't the one the other end is expecting. */
#if !APR_CHARSET_EBCDIC
/** linefeed */
#define LF 10
/** carrige return */
#define CR 13
/** carrige return /Line Feed Combo */
#define CRLF "\015\012"
#else /* APR_CHARSET_EBCDIC */
/* For platforms using the EBCDIC charset, the transition ASCII->EBCDIC is done
 * in the buff package (bread/bputs/bwrite).  Everywhere else, we use
 * "native EBCDIC" CR and NL characters. These are therefore
 * defined as
 * '\r' and '\n'.
 */
#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"
#endif /* APR_CHARSET_EBCDIC */

#define ATHD_CMD_STR_STREAM    "STREAM" CRLF
#define ATHD_CMD_STR_SHELL     "SHELL" CRLF

#define ATHD_PHYS_ALL          "*"
#define ATHD_FARM_ALL          "*"

/* log levels */
#define ATHD_CORE              0        
#define ATHD_CRIT              1
#define ATHD_WARN              2
#define ATHD_NOTE              3
#define ATHD_INFO              4       
#define ATHD_DEBUG             9
#define ATHD_DEVEL             99

#define ATHD_SHUTDOWN          0
#define ATHD_STOP              1
#define ATHD_START             3

#define ATHD_USER_AGENT        ATH_PKG_V " agent"
#define ATHD_HTTP_METHOD       "GET" 
#define ATHD_HTTP_VERS         "HTTP/1.1"

/* abstract data types */
typedef enum athd_job_type athd_job_type;
typedef enum athd_req_type athd_req_type;
typedef enum athd_cmd_type athd_cmd_type;
typedef enum athd_cmd_act athd_cmd_act;
typedef struct athd_connection athd_connection;
typedef struct athd_cmd_handler athd_cmd_handler;
typedef struct athd_cmd_req athd_cmd_req;
typedef struct athd_cmd athd_cmd; /* << this one is opaque */
typedef struct athd_cmd_ctx athd_cmd_ctx; /* << this one is opaque */
typedef struct athd_request athd_request;
typedef struct athd_response athd_response;
typedef struct athd_engine athd_engine;
typedef struct athd_job athd_job;
typedef struct athd_conf_os athd_conf_os;
typedef struct athd_conf athd_conf;
typedef struct athd_conf_prop athd_conf_prop;
typedef struct athd_mail athd_mail;
typedef struct athd_ip_farm athd_ip_farm;

/* func param types */
typedef const char *(*athd_conf_func) (athd_conf *conf, char *arg, char *pararg);
typedef int (*athd_sig_func) (int sig);
typedef float (*athd_stats_func) ();
#ifndef pthread_func_t
typedef void * (*pthread_func_t) (void *);
#endif

/* the gory details */
enum athd_job_type {
    ATHD_JOB_NON,
    ATHD_JOB_MON,
    ATHD_JOB_MIR,
    ATHD_JOB_AGT
};

enum athd_req_type {
    ATHD_REQ_UPDATE_PHYS,
    ATHD_REQ_UPDATE_FARM,
    ATHD_REQ_SERIAL_PHYS,
    ATHD_REQ_SERIAL_FARM,
    ATHD_REQ_MIRROR_PHYS,
    ATHD_REQ_MIRROR_FARM,
    ATHD_REQ_HELLO
};

enum athd_cmd_type {
    ATHD_CMD_SHELL,
    ATHD_CMD_STREAM,
};

enum athd_cmd_act {
    ATHD_ACT_CONTINUE,
    ATHD_ACT_STOP,
};

/* this is used to track reqs using a connection so we can cleanly
   cleanup connections
*/
struct athd_connection {
    apr_pool_t *pool;
    serf_connection_t *serf_conn;
    int ref_count;
    int retire;
    int use_ssl;
    pthread_mutex_t *mutex;
};

/* used by listener to handle client connection */
struct athd_cmd_handler {
    apr_pool_t *pool;
    pthread_t *thread;
    pthread_func_t thread_func;
    apr_socket_t *socket;
    athd_cmd_type type;
    char *prompt;
    ath_list *history;
    apr_int64_t id;
    athd_cmd_ctx *cmd_ctx; /* pass to next cmd */
};

struct athd_cmd_req {
    apr_pool_t *pool;
    athd_cmd_handler *handler;
    apr_bucket_alloc_t *ba_recv;
    apr_bucket_brigade *bb_recv;
    apr_bucket_alloc_t *ba_send;
    apr_bucket_brigade *bb_send;
    apr_size_t tosend;
    apr_size_t recved;
};

/* we move things into conn that are identical for all req */
typedef apr_status_t (*athd_response_handler) (serf_request_t *req);
struct athd_request {
    apr_pool_t *pool;
    char *url;
    athd_req_type type;
    serf_request_t *serf_request;
    serf_response_t *serf_response;
    athd_response_handler response_handler;
    athd_engine *engine;
    athd_job *job;
    apr_uri_t *uri;
    apr_size_t content_length;
    char *response_txt;
    int tries;
    apr_time_t expires;
    athd_connection *conn;
    pthread_cond_t *response_cv;
    pthread_mutex_t *response_mx;
    int cacheable;
    int cached;
};

/* 1 engine -> 1 thread */
struct athd_engine {
    apr_pool_t *pool;
    int dienow;
    char *name;
    char *url;
    apr_uri_t *uri;
    ath_list *secondaries; /* list el type athd_engine */
    athd_connection *conn_current; /* our current connection */
    ath_list *request_q;
    int use_ssl;
    int keep_alive;
    int request_q_limit;
    /* thread for this engine */
    pthread_t *thread;
    pthread_mutex_t *mutex;
    int refusing;
    int slow_server_factor;
    int ip_enable;
    ath_phys *clone_map_phys[ATH_PHYS_HARDMAX];
    ath_farm *clone_map_farm[ATH_FARM_HARDMAX];
    apr_time_t clone_map_farm_mtime;
    apr_time_t clone_map_phys_mtime;
    apr_time_t clone_map_expire;
    apr_hash_t *request_resp_cache;
};

/* a job associates with a logical task like monitoring */
/* 1 job -> 1 thread */
struct athd_job {
    apr_pool_t *pool;
    char *name;
    athd_job_type type;
    int on;
    /* frequency */
    int freq;
    /* wait is set to freq, then (wait-- per/by tick) */
    /* 0 = ready to run */
    int wait;
    /* how man iterations to live */
    int iter_lives;
    /* current iteration count */
    int iter_count;
    /* mail on or off */
    int mail; 
    ath_list *mailaddrs;
    char *replyto;
    apr_time_t mail_resend_throttle;
    /* list of engines to which this job is applied */
    /* ** now just one engine for simplicity ** */
    /* ath_list *engines; */
    athd_engine *engine;
    /* list of requests made, they are delivered here when response comes */
    pthread_mutex_t *response_q_mutex;
    ath_list *response_q;
    /* thread for this job */
    pthread_t *thread;
    pthread_mutex_t *mutex;
    int dienow;
};

/* system level layout (not athena layout) */
struct athd_conf_os {
    char *path_shell;
    char *path_sendmail;
};

struct athd_conf_prop {
    const char *name;
    athd_conf_func func;
    const char *parent;
};

struct athd_ip_farm {
    const char *name;
    int farm_port;
    int phys_port;
};

/* core daemon conf */
struct athd_conf {
    apr_pool_t *pool;
    int debug;
    int passchecks;
    char *server_name;
    char *use_shm;
    char *log_lock_path;
    char *use_apconf;
    athd_directive *ap_conf_tree;
    apr_uid_t uid;
    apr_uid_t gid;
    apr_port_t port;
    char *pidfile;
    char *logfile;
    int syslog_fac;
    athd_conf_os *os;
    athd_job *job_proto;
    ath_list *engines;
    ath_list *jobs;
    int ip_lb;
    int ip_divertport;
    int ip_deny;
    int ip_sockets;
    ath_list *ip_farms;
    int stats_pulse;
};

struct athd_mail {
    apr_pool_t *pool; /* per-message pool */
    char *to;
    char *replyto;
    char *subject;
    char *body;
};

#endif /* ATHD_D */
